﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ConsolidationTool.Common;
using System.Web.Script.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.Collections;
using System.Reflection;

namespace ConsolidationTool.WebParts.Layouts.AjaxServices
{
    public class MergeServices : IAjaxService
    {
        private FSSearchEntity ClientSearchEntity;
        private JavaScriptSerializer jsSerializer;
        private RateServices rateServices;
        private string InputType { get; set; }
        private string ForceRateType { get; set; }
        public AjaxResult Excute(System.Web.HttpContext context, FSSearchEntity searchEntity)
        {
            ClientSearchEntity = searchEntity;
            InputType = ClientSearchEntity.ListTitle.Split('_')[1];
            
            rateServices = new RateServices();
            jsSerializer = new JavaScriptSerializer();
            BaseMerge<BaseMergeRow> merge = null;

            if (InputType == "Actual")
            {
                merge = jsSerializer.Deserialize<ActualMerge>(searchEntity.Data).Convert();
            }
            else if (InputType == "Flash")
            {
                merge = jsSerializer.Deserialize<ActualMerge>(searchEntity.Data).Convert();
            }
            else if (InputType == "Budget")
            {
                merge = jsSerializer.Deserialize<BudgetMerge>(searchEntity.Data).Convert();
            }
            else if (InputType == "Forecast")
            {
                merge = jsSerializer.Deserialize<ForecastMerge>(searchEntity.Data).Convert();
            }
            merge.RegionCode = searchEntity.CompanyCode;
            merge.Year = searchEntity.Year;
            merge.Month = searchEntity.Month;
            ForceRateType = merge.ForceRateType;

            var rows = MergeRegionData(merge);

            return new AjaxResult(true, rows);
        }

        private string GetRealListTitleFromInputType(string title)
        {
            string shortListTitle = string.Empty, longListTitle = string.Empty; ;
            switch (title)
            {
                case "HR":
                    shortListTitle = "HR";
                    longListTitle = "HR";
                    break;
                case "QS":
                    shortListTitle = "QS";
                    longListTitle = "Quality&Safety";
                    break;
                case "PSBR":
                    shortListTitle = "PSBR";
                    longListTitle = "Product Sales By RGC";
                    break;
                case "TSBR":
                    shortListTitle = "TSBR";
                    longListTitle = "Trade Sales By RGC";
                    break;
                case "SCS":
                    shortListTitle = "SCS";
                    longListTitle = "Sales&Commission&Service";
                    break;
                case "SBEW":
                    shortListTitle = "SBEW";
                    longListTitle = "SBEW";
                    break;
                case "GRFC":
                    shortListTitle = "GRFC";
                    longListTitle = "Gross Fixed Cost";
                    break;
                case "ES":
                    shortListTitle = "ES";
                    longListTitle = "External Services";
                    break;
                case "FSA":
                    shortListTitle = "FSA";
                    longListTitle = "FC_SG_A";
                    break;
                case "Depreciation":
                    shortListTitle = "Depreciation";
                    longListTitle = "Depreciation";
                    break;
                case "P_L":
                    shortListTitle = "PL";
                    longListTitle = "P_L";
                    break;
                case "PL":
                    shortListTitle = "PL";
                    longListTitle = "P_L";
                    break;
                case "DCF":
                    shortListTitle = "DCF";
                    longListTitle = "Direct Cash flow";
                    break;
                case "CAPEX":
                    shortListTitle = "CAPEX";
                    longListTitle = "CAPEX";
                    break;
                case "Inventory":
                    shortListTitle = "Inventory";
                    longListTitle = "Inventory";
                    break;
                case "BS":
                    shortListTitle = "BS";
                    longListTitle = "Balance Sheet";
                    break;
                case "ICF":
                    shortListTitle = "ICF";
                    longListTitle = "Indirect Cash flow";
                    break;
            }

            return longListTitle;
        }
        public List<CacheSPItem> AllItemsOfRegion { get; set; }

        private object MergeRegionData(BaseMerge<BaseMergeRow> merge)
        {
            try
            {

                string OriginalListTitle = merge.isKoMode ? merge.OriginalTitle : GetRealListTitleFromInputType(merge.OriginalTitle);

                var list = SPContext.Current.Web.Lists.TryGetList(OriginalListTitle);
                if (list == null)
                    SPUtility.HandleAccessDenied(new Exception(merge.OriginalTitle + " can not found"));

                AllItemsOfRegion = GetAllItemsOfRegion(list, merge.RegionCode, merge.Year, merge.Month);
                var allInternalSalesItems = new List<CacheSPItem>();
                string internalSalesListTitle = "Sales Interco Declaration";

                if (merge.Title.IndexOf("Budget_") != -1)
                    internalSalesListTitle = "Budget_SID";
                if (merge.Title.IndexOf("Forecast_") != -1)
                    internalSalesListTitle = "Forecast_SID";

                allInternalSalesItems = GetAllItemsOfRegion(SPContext.Current.Web.Lists.TryGetList(internalSalesListTitle), merge.RegionCode, merge.Year, merge.Month);

                if (merge.isKoMode)
                    return merge.Process(AllItemsOfRegion, allInternalSalesItems);
                else
                    return merge.UnKoProcess(AllItemsOfRegion, allInternalSalesItems);

            }
            catch (Exception ex)
            {

                throw ex;
                return null;
            }
            //if (merge is ActualMerge)
            //{
            //    return ActualProcess(merge as ActualMerge);
            //}
            //else if (merge is BudgetMerge)
            //{
            //    return BudgetProcess(merge as BudgetMerge);
            //} 
            //else if (merge is ForecastMerge)
            //{
            //    return ForecastProcess(merge as ForecastMerge);
            //}

        }

        /*
        public List<ActualMergeRow> ActualProcess(ActualMerge merge)
        {
            merge.Rows.ForEach(p =>
            {
                if (p.Process == null)
                {
                    decimal CMTmp = 0, YTDM1Tmp = 0, YTDTmp = 0;
                    AllItemsOfRegion.ForEach(item =>
                    {
                        var currentCurrency = ExchangeRageList.FirstOrDefault(a => a.FC == item.LocalCurrency);

                        var CMItemValue = BusinessService.decimalParse(item["CM_" + p.accountcode]);
                        var YTDM1ItemValue = BusinessService.decimalParse(item["YTDM1_" + p.accountcode]);
                        var YTDItemValue = (CMItemValue + YTDM1ItemValue);
                        if (p.exchangerate)
                        {
                            var rateCM = currentCurrency != null ? currentCurrency.CM : "0";
                            var rateYTD = currentCurrency != null ? currentCurrency.YTD : "0";
                            var rateYTDM_1 = currentCurrency != null ? currentCurrency.YTDM_1 : "0";
                            p.Log += string.Format("<b>({0})</b>({3})C:{4},Y:{5} Original:[C:({1}),Y:({2})]", item.CoName, ColorHightLight(CMItemValue), ColorHightLight(YTDItemValue), item.LocalCurrency, rateCM, rateYTD);

                            //process exchange rate
                            CMItemValue = FixExchangeRate(CMItemValue, rateCM);
                            YTDM1ItemValue = FixExchangeRate(YTDM1ItemValue, rateYTDM_1);
                            YTDItemValue = FixExchangeRate(YTDItemValue, rateYTD);

                            p.Log += string.Format(" / <b>After:</b>[C:({0}),Y:({1})] <br/>", ColorHightLight(CMItemValue), ColorHightLight(YTDItemValue));
                        }

                        CMTmp += CMItemValue;
                        YTDM1Tmp += YTDM1ItemValue;
                        YTDTmp += YTDItemValue;
                    });

                    p.CM = CMTmp;
                    p.YTDM_1 = YTDM1Tmp;
                    p.YTD = YTDTmp;
                }
            });

            return merge.Rows;
        }

        private List<BudgetMergeRow> BudgetProcess(BudgetMerge baseMerge)
        {
            baseMerge.Rows.Where(p => p.datarow).ToList().ForEach(p =>
            {
                if (p.Process == null)
                {
                    List<string> properties = p.GetType().GetProperties(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public).Select(a => a.Name).ToList();

                    AllItemsOfRegion.ForEach(regItem =>
                    {
                        var row = regItem.KoFields.FirstOrDefault(c => c.accountcode == p.accountcode);

                        properties.ForEach(pro =>
                        {
                            var oldValue = BusinessService.decimalParse(row.TryGetValue(pro) + "");
                            var newValue = BusinessService.decimalParse(p.TryGetValue(pro) + "");

                            if (p.exchangerate)
                                newValue += FixExchangeRate(oldValue, regItem.ExchangeRate.CM);
                            else
                                newValue += oldValue;

                            p.TrySetValue(pro, newValue);
                        });

                    });
                }


            });

            return baseMerge.Rows;
        }

        private object ForecastProcess(ForecastMerge forecastMerge)
        {
            forecastMerge.Rows.Where(p => p.datarow).ToList().ForEach(p =>
            {
                if (p.Process == null)
                {
                    List<string> properties = p.GetType().GetProperties(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public).Select(a => a.Name).ToList();

                    AllItemsOfRegion.ForEach(regItem =>
                    {
                        var row = regItem.KoFields.FirstOrDefault(c => c.accountcode == p.accountcode);

                        properties.ForEach(pro =>
                        {
                            var oldValue = BusinessService.decimalParse(row.TryGetValue(pro) + "");
                            var newValue = BusinessService.decimalParse(p.TryGetValue(pro) + "");

                            if (p.exchangerate)
                                newValue += FixExchangeRate(oldValue, regItem.ExchangeRate.TryGetValue(pro) + "");
                            else
                                newValue += oldValue;

                            p.TrySetValue(pro, newValue);
                        });

                    });
                }
            });

            return forecastMerge.Rows;
        }
        */


        #region BaseSupport

        private List<ExchangeRate> _exchangeRate;
        public List<ExchangeRate> ExchangeRageList
        {
            get
            {
                if (_exchangeRate == null)
                {
                    _exchangeRate = LoadExchangeRate();
                    if (ClientSearchEntity.ListTitle.Contains("_VM")) {
                        var date = DateTime.Parse(string.Format("{0}-{1}-01 00:00:01", ClientSearchEntity.Year, ClientSearchEntity.Month));

                        _exchangeRate.AddRange(rateServices.LoadExchangeRate("Actual", date.AddYears(-1).Year + "", date.AddYears(-1).Month + "", "N-1"));

                        _exchangeRate.AddRange(rateServices.LoadExchangeRate("Budget", ClientSearchEntity.Year, string.Empty, "Y"));
                        _exchangeRate.AddRange(rateServices.LoadExchangeRate("Forecast", ClientSearchEntity.Year, ClientSearchEntity.Month, "Y"));

                    }
                }
                return _exchangeRate;
            }
        }

        private List<ExchangeRate> LoadExchangeRate() {
            string inputType = ForceRateType.IsNotNullOrEmpty() ? ForceRateType : ClientSearchEntity.ListTitle.Split('_')[1];
            return rateServices.LoadExchangeRate(inputType, ClientSearchEntity.Year, ClientSearchEntity.Month, "Original");
        }


        private List<CacheSPItem> GetAllItemsOfRegion(SPList list, string region, string year, string month)
        {
            var tmp = new List<CacheSPItem>();
            if (list == null) return tmp;

            var query = new SPQuery()
            {
                Query = string.Format(@"   <Where>
                  <And>
                     <Eq>
                        <FieldRef Name='Region' />
                        <Value Type='Text'>{0}</Value>
                     </Eq>
                     <And>
                        <Eq>
                           <FieldRef Name='Year' />
                           <Value Type='Integer'>{1}</Value>
                        </Eq>
                        <Eq>
                           <FieldRef Name='Month' />
                           <Value Type='Integer'>{2}</Value>
                        </Eq>
                     </And>
                  </And>
               </Where>", region, year, month)
            };

            if (month.IsNullOrEmpty() || month == "0")
            {
                query = new SPQuery()
                {
                    Query = string.Format(@"  <Where>
      <And>
         <Eq>
            <FieldRef Name='Region' />
            <Value Type='Text'>{0}</Value>
         </Eq>
         <Eq>
            <FieldRef Name='Year' />
            <Value Type='Integer'>{1}</Value>
         </Eq>
      </And>
   </Where>", region, year)
                };
            }

            var items = list.GetItems(query);
            int itemCount = items.Count;
            for (int i = 0; i < itemCount; i++)
            {
                var newCacheItem = new CacheSPItem(items[i]);
                newCacheItem.ExchangeRate = ExchangeRageList.Where(p => p.FC == newCacheItem.LocalCurrency).ToList();
                if (newCacheItem.ExchangeRate == null)
                    newCacheItem.ExchangeRate = new List<ExchangeRate>();

                tmp.Add(newCacheItem);
            }
            return tmp;
        }

        #endregion


    }
}
